package com.hnxxxy.oa.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hnxxxy.oa.enums.BizCodeEnum;
import com.hnxxxy.oa.exception.BizException;
import com.hnxxxy.oa.system.constant.MenuType;
import com.hnxxxy.oa.system.mapper.SysMenuMapper;
import com.hnxxxy.oa.system.mapper.SysRoleMenuMapper;
import com.hnxxxy.oa.system.model.SysMenuDO;
import com.hnxxxy.oa.system.model.SysRoleMenuDO;
import com.hnxxxy.oa.system.request.MenuAddRequest;
import com.hnxxxy.oa.system.request.MenuUpdateRequest;
import com.hnxxxy.oa.system.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 周石林
* @description 针对表【sys_menu(菜单)】的数据库操作Service实现
* @createDate 2022-05-03 15:33:12
*/
@Service
@Slf4j
public class SysMenuServiceImpl implements SysMenuService{

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public Integer addMenu(MenuAddRequest menuAddRequest) {
        Integer parentId = menuAddRequest.getParentId();
        Integer type = menuAddRequest.getType();
        String menuName = menuAddRequest.getMenuName();
        //目录类型处理
        if(type== MenuType.CATALOG){
            //子目录处理
            if(parentId!=0){
                //上级是否是目录类型
                QueryWrapper<SysMenuDO> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id",parentId);
                queryWrapper.eq("type",MenuType.CATALOG);
                if(sysMenuMapper.selectCount(queryWrapper)==0){
                    throw new BizException(BizCodeEnum.DIRECTORY_UNEXIST);
                }
                //是否有同名目录目录
                queryWrapper=new QueryWrapper<>();
                queryWrapper.eq("menu_name",menuName);
                queryWrapper.eq("parent_id",parentId);
                if(sysMenuMapper.selectCount(queryWrapper)>0){
                    throw new BizException(BizCodeEnum.DIRECTORY_REPEAT);
                }
            }
            //一级目录处理
            //检查是否有同名目录
            QueryWrapper<SysMenuDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("menu_name",menuName);
            queryWrapper.eq("parent_id",MenuType.CATALOG);
            if(sysMenuMapper.selectCount(queryWrapper)>0){
                throw new BizException(BizCodeEnum.DIRECTORY_REPEAT);
            }
        }
        //菜单类型处理
        if(type== MenuType.MENU) {
            //上级是否是目录类型
            QueryWrapper<SysMenuDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id", parentId);
            queryWrapper.eq("type",MenuType.CATALOG);
            if (sysMenuMapper.selectCount(queryWrapper)== 0) {
                //不存在上级目录抛出异常
                throw new BizException(BizCodeEnum.PARENTCATALOGUE_UNEXIST);
            }
            //是否有同名菜单
            queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("menu_name",menuName);
            queryWrapper.eq("parent_id",parentId);
            if (sysMenuMapper.selectCount(queryWrapper)>0) {
                throw new BizException(BizCodeEnum.MENU_EXIST);
            }
        }
        //按钮类型处理
        if(type==MenuType.BUTTON){
            //上级是否是菜单类型
            QueryWrapper<SysMenuDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",parentId);
            queryWrapper.eq("type",1);
            if(sysMenuMapper.selectCount(queryWrapper)==0){
                throw new BizException(BizCodeEnum.PARENTMENU_UNEXIST);
            }
            //是否有同名按钮
            queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("parent_id",parentId);
            queryWrapper.eq("menu_name",menuName);
            if(sysMenuMapper.selectCount(queryWrapper)>0){
                throw new BizException(BizCodeEnum.BUTTON_REPEAT);
            }
        }
        //将请求对象转换为菜单实体类
        SysMenuDO sysMenuDO = new SysMenuDO();
        sysMenuDO.setParentId(parentId);
        sysMenuDO.setMenuName(menuName);
        sysMenuDO.setUrl(menuAddRequest.getUrl());
        sysMenuDO.setMenuOrder(menuAddRequest.getMenuOrder());
        sysMenuDO.setPermission(menuAddRequest.getPermission());
        sysMenuDO.setType(type);
        sysMenuMapper.insert(sysMenuDO);
        return sysMenuDO.getId();
    }

    @Override
    public boolean updateMenu(MenuUpdateRequest menuUpdateRequest) {
        Integer id = menuUpdateRequest.getId();
        SysMenuDO sysMenuDO = sysMenuMapper.selectById(id);
        if(sysMenuDO==null){
            throw new BizException(BizCodeEnum.DIRECTORY_UNEXIST);
        }
        //删除菜单
        deleteMenu(id);
        //将菜单类型转换为添加菜单请求对象类型
        MenuAddRequest menuAddRequest = new MenuAddRequest();
        menuAddRequest.setParentId(menuUpdateRequest.getParentId());
        menuAddRequest.setMenuName(menuUpdateRequest.getMenuName());
        menuAddRequest.setUrl(menuUpdateRequest.getUrl());
        menuAddRequest.setMenuOrder(menuUpdateRequest.getMenuOrder());
        menuAddRequest.setPermission(menuUpdateRequest.getPermission());
        menuAddRequest.setType(menuUpdateRequest.getType());
        //添加菜单
        Integer integer = addMenu(menuAddRequest);
        //更新指向删除菜单的ParentId（因为重新添加菜单改变菜单id）
        List<SysMenuDO> menus = list();
        List<SysMenuDO> collect = menus.stream().filter(menu -> menu.getParentId().equals(id))
                .map(menu -> {
                    menu.setParentId(integer);
                    return menu;
                }).collect(Collectors.toList());
        for (SysMenuDO menuDO : collect) {
            sysMenuMapper.updateById(menuDO);
        }
        //更新角色授权表的menuId
        QueryWrapper<SysRoleMenuDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("menu_id",id);
        List<SysRoleMenuDO> sysRoleMenuDOS = sysRoleMenuMapper.selectList(queryWrapper);
        List<SysRoleMenuDO> collect1 = sysRoleMenuDOS.stream().filter(roleMenu -> roleMenu.getMenuId().equals(id))
                .map(roleMenu -> {
                    roleMenu.setMenuId(integer);
                    return roleMenu;
                }).collect(Collectors.toList());
        for (SysRoleMenuDO sysRoleMenuDO : collect1) {
            sysRoleMenuMapper.updateById(sysRoleMenuDO);
        }
        return true;
    }

    @Override
    public boolean deleteMenu(Integer id) {
        SysMenuDO sysMenuDO = sysMenuMapper.selectById(id);
        if(sysMenuDO==null){
            throw new BizException(BizCodeEnum.MENU_UNEXIST);
        }
        int i = sysMenuMapper.deleteById(id);
        return i==1;
    }

    @Override
    public List<SysMenuDO> listWithTree() {
        //查出所有分类
        List<SysMenuDO> menus = sysMenuMapper.selectList(null);
        //组装成父子结构

        //找出所有的一级分类
        List<SysMenuDO> level1 = menus.stream().filter(menu -> menu.getParentId() == 0)
                .map(menu->{
                    //找出子菜单
                    menu.setChilds(getChildrens(menu,menus));
                    return menu;
                })
                .sorted((menu1,menu2)->menu1.getMenuOrder()-menu2.getMenuOrder())
                .collect(Collectors.toList());
        return level1;
    }

    @Override
    public List<SysMenuDO> list() {
        return sysMenuMapper.selectList(null);
    }

    @Override
    public List<SysMenuDO> getList() {
        QueryWrapper<SysMenuDO> sysMenuDOQueryWrapper = new QueryWrapper<>();
        sysMenuDOQueryWrapper.ne("type",2);
        return sysMenuMapper.selectList(sysMenuDOQueryWrapper);
    }

    private List<SysMenuDO> getChildrens(SysMenuDO sysMenuDO,List<SysMenuDO> menus){
        //如果是按钮则不显示
        if (sysMenuDO.getType()==MenuType.BUTTON){
            return null;
        }
        return menus.stream().filter(menu -> menu.getParentId().equals(sysMenuDO.getId()))
                .map(menu -> {
                    menu.setChilds(getChildrens(menu,menus));
                    return menu;
                })
                .sorted((menu1,menu2)->menu1.getMenuOrder()-menu2.getMenuOrder())
                .collect(Collectors.toList());
    }
}